using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using Sinacor.Infra.Service.Common;
using Sinacor.Infra.Service.Data;
using Sinacor.Infra.Service.Security.Authorization;

namespace Sinacor.Servico.Bovespa.Corretagem.ResourceAccess
{
    /// <summary>
    /// Acesso a dados de política de corretagem
    /// </summary>
    public class PoliticaCorretagem : BaseResourceAccess
    {
        #region Construtor

        /// <summary>
        /// Construtor PoliticaCorretagem
        /// </summary>
        public PoliticaCorretagem()
            : base(AuthorizationContext.Current.CompanyId)
        {
        }

        #endregion

        #region Métodos

        /// <summary>
        /// Consulta no banco de dados quais as políticas corretagens que atendem ao
        /// critério do filtro
        /// </summary>
        /// <param name="entity"></param>
        public List<BusinessEntity.PoliticaCorretagem> ConsultarPoliticasCorretagens(BusinessEntity.Parameter.FiltroPoliticaCorretagem entity)
        {
            List<BusinessEntity.PoliticaCorretagem> listaPoliticaCorretagem = null;
            List<BusinessEntity.TabelaCorretagem> listaTabelaCorretagem = null;
            List<BusinessEntity.TipoAplicacaoPolitica> listaTipoAplicacaoPolitica = null;
            StringBuilder sql = new StringBuilder();

            listaTabelaCorretagem = new TabelaCorretagem().ConsultarTabelasCorretagem(new BusinessEntity.Parameter.FiltroTabelaCorretagem());
            listaTipoAplicacaoPolitica = new TipoAplicacaoPolitica().ConsultarTipoAplicacaoPolitica(new BusinessEntity.Parameter.FiltroTipoAplicacaoPolitica());

            using (DbCommand command = this.DataBase.GetSqlStringCommand(" "))
            {
                sql.AppendLine("SELECT");
                sql.AppendLine("    CD_POLITICA Codigo,");
                sql.AppendLine("    DT_INICIAL DataInicial,");
                sql.AppendLine("    DT_FINAL DataFinal,");
                sql.AppendLine("    DS_POLITICA Descricao,");
                sql.AppendLine("    CD_TIPO_APLIC TipoAplicacao,");
                sql.AppendLine("    CD_TABELA TabelaPadrao,");
                sql.AppendLine("    CD_TABELA_BENEF TabelaBeneficio,");
                sql.AppendLine("    IN_VERIF EfetuarVerificacao,");
                sql.AppendLine("    IN_CTRL_BENEF TipoControleBeneficio");
                sql.AppendLine("FROM");
                sql.AppendLine("    TBOCORR_POLI");
                sql.AppendLine("WHERE 1 = 1");

                //Filtros Opcionais
                if (entity.Codigo.HasValue)
                {
                    sql.AppendLine("AND CD_POLITICA = :Codigo");
                    this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                }

                if (entity.DataInicial.HasValue)
                {
                    sql.AppendLine("AND DT_INICIAL >= :DataInicial");
                    this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);
                }

                if (entity.DataFinal.HasValue)
                {
                    sql.AppendLine("AND DT_FINAL <= :DataFinal");
                    this.DataBase.AddInParameter(command, "DataFinal", DbType.DateTime, entity.DataFinal);
                }

                if (!string.IsNullOrEmpty(entity.Descricao))
                {
                    sql.AppendLine("AND UPPER(DS_POLITICA) = :Descricao");
                    this.DataBase.AddInParameter(command, "Descricao", DbType.String, entity.Descricao.ToUpper());
                }

                if (entity.TipoAplicacao != null && entity.TipoAplicacao.Codigo != null)
                {
                    sql.AppendLine("AND CD_TIPO_APLIC = :TipoAplicacao");
                    this.DataBase.AddInParameter(command, "TipoAplicacao", DbType.Int32, entity.TipoAplicacao.Codigo);
                }

                if (entity.TabelaPadrao != null && entity.TabelaPadrao.Codigo != null)
                {
                    sql.AppendLine("AND CD_TABELA = :TabelaPadraoCodigo");
                    this.DataBase.AddInParameter(command, "TabelaPadraoCodigo", DbType.String, entity.TabelaPadrao.Codigo);
                }

                if (entity.TabelaBeneficio != null && entity.TabelaBeneficio.Codigo != null)
                {
                    sql.AppendLine("AND CD_TABELA_BENEF = :TabelaBeneficioCodigo");
                    this.DataBase.AddInParameter(command, "TabelaBeneficioCodigo", DbType.String, entity.TabelaBeneficio.Codigo);
                }

                if (entity.EfetuarVerificacao.HasValue)
                {
                    sql.AppendLine("AND IN_VERIF = :EfetuarVerificacao");
                    this.DataBase.AddInParameter(command, "EfetuarVerificacao", DbType.Boolean, entity.EfetuarVerificacao);
                }

                if (entity.TipoControleBeneficio.HasValue)
                {
                    sql.AppendLine("AND IN_CTRL_BENEF = :TipoControleBeneficio");
                    this.DataBase.AddInParameter(command, "TipoControleBeneficio", DbType.String, EnumConverter.ToString<BusinessEntity.Enum.TipoControleBeneficio?>(entity.TipoControleBeneficio));
                }

                command.CommandText = sql.ToString();

                listaPoliticaCorretagem = this.FindAll<BusinessEntity.PoliticaCorretagem>(command, reader => new BusinessEntity.PoliticaCorretagem

                {
                    Codigo = reader.GetValue<int>("Codigo"),
                    DataFinal = reader.GetValue<DateTime>("DataFinal"),
                    DataInicial = reader.GetValue<DateTime>("DataInicial"),
                    Descricao = (reader["Descricao"] != DBNull.Value ? reader.GetValue<string>("Descricao") : String.Empty),
                    TipoAplicacao = new BusinessEntity.TipoAplicacaoPolitica { Codigo = (reader["TipoAplicacao"] != DBNull.Value ? reader.GetValue<int?>("TipoAplicacao") : null) },
                    TabelaPadrao = new BusinessEntity.TabelaCorretagem { Codigo = (reader["TabelaPadrao"] != DBNull.Value ? reader.GetValue<int?>("TabelaPadrao") : null) },
                    TabelaBeneficio = new BusinessEntity.TabelaCorretagem { Codigo = (reader["TabelaBeneficio"] != DBNull.Value ? reader.GetValue<int?>("TabelaBeneficio") : null) },
                    EfetuarVerificacao = (reader["EfetuarVerificacao"] != DBNull.Value ? (bool?)(reader.GetValue<string>("EfetuarVerificacao").ToUpper().Equals("S") ? true : false) : null),
                    TipoControleBeneficio = (reader["TipoControleBeneficio"] != DBNull.Value ? EnumConverter.Parse<BusinessEntity.Enum.TipoControleBeneficio?>(reader.GetValue<string>("TipoControleBeneficio")) : null)
                });
            }

            listaPoliticaCorretagem.ForEach(item =>
                listaTabelaCorretagem.ForEach(tabelaPadrao =>
                {
                    if (item.TabelaPadrao.Codigo.HasValue && item.TabelaPadrao.Codigo.Equals(tabelaPadrao.Codigo))
                    {
                        item.TabelaPadrao = tabelaPadrao;
                    }
                })
            );

            listaPoliticaCorretagem.ForEach(item =>
                listaTipoAplicacaoPolitica.ForEach(tipoAplicacao =>
                {
                    if (item.TipoAplicacao.Codigo.HasValue && item.TipoAplicacao.Codigo.Equals(tipoAplicacao.Codigo))
                    {
                        item.TipoAplicacao = tipoAplicacao;
                    }
                })
            );

            return listaPoliticaCorretagem;
        }

        /// <summary>
        /// Obtem uma entidade de política de corretagem
        /// </summary>
        /// <param name="entity"></param>
        public BusinessEntity.PoliticaCorretagem ObterPoliticaCorretagem(BusinessEntity.Parameter.FiltroPoliticaCorretagemChave entity)
        {
            BusinessEntity.PoliticaCorretagem politicaCorretagem = null;
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("SELECT");
            sql.AppendLine("    CD_POLITICA AS Codigo,");
            sql.AppendLine("    DT_INICIAL AS DataInicial,");
            sql.AppendLine("    DT_FINAL AS DataFinal,");
            sql.AppendLine("    DS_POLITICA AS Descricao,");
            sql.AppendLine("    CD_TIPO_APLIC AS TipoAplicacao,");
            sql.AppendLine("    CD_TABELA AS TabelaPadrao,");
            sql.AppendLine("    CD_TABELA_BENEF AS TabelaBeneficio,");
            sql.AppendLine("    IN_VERIF AS EfetuarVerificacao,");
            sql.AppendLine("    IN_CTRL_BENEF AS TipoControleBeneficio");
            sql.AppendLine("FROM");
            sql.AppendLine("    TBOCORR_POLI");
            sql.AppendLine("WHERE");
            sql.AppendLine("    CD_POLITICA  = :Codigo");
            sql.AppendLine("AND DT_INICIAL = :DataInicial");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {

                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);

                politicaCorretagem = this.FindOne<BusinessEntity.PoliticaCorretagem>(command, reader => new BusinessEntity.PoliticaCorretagem
                {
                    Codigo = reader.GetValue<int>("Codigo"),
                    DataFinal = reader.GetValue<DateTime>("DataFinal"),
                    DataInicial = reader.GetValue<DateTime>("DataInicial"),
                    Descricao = (reader["Descricao"] != DBNull.Value ? reader.GetValue<string>("Descricao") : string.Empty),
                    EfetuarVerificacao = (reader["EfetuarVerificacao"] != DBNull.Value ? (bool?)(reader.GetValue<string>("EfetuarVerificacao").ToUpper().Equals("S") ? true : false) : null),
                    TabelaBeneficio = (reader["TabelaBeneficio"] != DBNull.Value ? new BusinessEntity.TabelaCorretagem { Codigo = reader.GetValue<int>("TabelaBeneficio") } : null),
                    TabelaPadrao = (reader["TabelaPadrao"] != DBNull.Value ? new BusinessEntity.TabelaCorretagem { Codigo = reader.GetValue<int>("TabelaPadrao") } : null),
                    TipoAplicacao = (reader["TipoAplicacao"] != DBNull.Value ? new BusinessEntity.TipoAplicacaoPolitica { Codigo = reader.GetValue<int>("TipoAplicacao") } : null),
                    TipoControleBeneficio = (reader["TipoControleBeneficio"] != DBNull.Value ? EnumConverter.Parse<BusinessEntity.Enum.TipoControleBeneficio?>(reader.GetValue<string>("TipoControleBeneficio")) : null)
                });
            }

            return politicaCorretagem;
        }

        /// <summary>
        /// Incluir uma nova politica de corretagem no banco de dados.
        /// </summary>
        /// <param name="entity"></param>
        public void IncluirPoliticaCorretagem(BusinessEntity.PoliticaCorretagem entity)
        {
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("INSERT INTO TBOCORR_POLI(");
            sql.AppendLine("    CD_POLITICA,");
            sql.AppendLine("    DT_INICIAL,");
            sql.AppendLine("    DT_FINAL,");
            sql.AppendLine("    DS_POLITICA,");
            sql.AppendLine("    CD_TIPO_APLIC,");
            sql.AppendLine("    CD_TABELA,");
            sql.AppendLine("    CD_TABELA_BENEF,");
            sql.AppendLine("    IN_VERIF,");
            sql.AppendLine("    IN_CTRL_BENEF)");
            sql.AppendLine("VALUES(");
            sql.AppendLine("    :Codigo,");
            sql.AppendLine("    :DataInicial,");
            sql.AppendLine("    :DataFinal,");
            sql.AppendLine("    :Descricao,");
            sql.AppendLine("    :TipoAplicacaoCodigo,");
            sql.AppendLine("    :TabelaPadraoCodigo,");
            sql.AppendLine("    :TabelaBeneficioCodigo,");
            sql.AppendLine("    :EfetuarVerificacao,");
            sql.AppendLine("    :TipoControleBeneficio)");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);
                this.DataBase.AddInParameter(command, "DataFinal", DbType.DateTime, entity.DataFinal);
                this.DataBase.AddInParameter(command, "Descricao", DbType.String, entity.Descricao);
                this.DataBase.AddInParameter(command, "TipoAplicacaoCodigo", DbType.Int32, (entity.TipoAplicacao != null ? entity.TipoAplicacao.Codigo : null));
                this.DataBase.AddInParameter(command, "TabelaPadraoCodigo", DbType.Int32, (entity.TabelaPadrao != null ? entity.TabelaPadrao.Codigo : null));
                this.DataBase.AddInParameter(command, "TabelaBeneficioCodigo", DbType.Int32, (entity.TabelaBeneficio != null ?entity.TabelaBeneficio.Codigo : null));
                this.DataBase.AddInParameter(command, "EfetuarVerificacao", DbType.String, (entity.EfetuarVerificacao.HasValue && entity.EfetuarVerificacao.Value ? "S" : "N"));
                this.DataBase.AddInParameter(command, "TipoControleBeneficio", DbType.String, EnumConverter.ToString<BusinessEntity.Enum.TipoControleBeneficio?>(entity.TipoControleBeneficio));

                this.DataBase.ExecuteNonQuery(command);
            }
        }
        /// <summary>
        /// Altera os dados de politica de corretagem no banco de dados.
        /// </summary>
        /// <param name="entity"></param>
        public void AlterarPoliticaCorretagem(BusinessEntity.PoliticaCorretagem entity)
        {
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("UPDATE");
            sql.AppendLine("    TBOCORR_POLI");
            sql.AppendLine("SET");
            sql.AppendLine("    DT_FINAL = :DataFinal,");
            sql.AppendLine("    DS_POLITICA = :Descricao,");
            sql.AppendLine("    CD_TIPO_APLIC = :TipoAplicacaoCodigo,");
            sql.AppendLine("    CD_TABELA = :TabelaPadraoCodigo,");
            sql.AppendLine("    CD_TABELA_BENEF = :TabelaBeneficioCodigo,");
            sql.AppendLine("    IN_VERIF = :EfetuarVerificacao,");
            sql.AppendLine("    IN_CTRL_BENEF = :TipoControleBeneficio");
            sql.AppendLine("WHERE");
            sql.AppendLine("    CD_POLITICA = :Codigo");
            sql.AppendLine("AND	DT_INICIAL = :DataInicial");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);
                this.DataBase.AddInParameter(command, "DataFinal", DbType.DateTime, entity.DataFinal);
                this.DataBase.AddInParameter(command, "Descricao", DbType.String, entity.Descricao);
                this.DataBase.AddInParameter(command, "TipoAplicacaoCodigo", DbType.Int32, (entity.TipoAplicacao != null ? entity.TipoAplicacao.Codigo : null));
                this.DataBase.AddInParameter(command, "TabelaPadraoCodigo", DbType.Int32, (entity.TabelaPadrao != null ? entity.TabelaPadrao.Codigo : null));
                this.DataBase.AddInParameter(command, "TabelaBeneficioCodigo", DbType.Int32, (entity.TabelaBeneficio != null ? entity.TabelaBeneficio.Codigo : null));
                this.DataBase.AddInParameter(command, "EfetuarVerificacao", DbType.String, (entity.EfetuarVerificacao.HasValue && entity.EfetuarVerificacao.Value ? "S" : "N"));
                this.DataBase.AddInParameter(command, "TipoControleBeneficio", DbType.String, EnumConverter.ToString<BusinessEntity.Enum.TipoControleBeneficio?>(entity.TipoControleBeneficio));

                this.DataBase.ExecuteNonQuery(command);
            }
        }
        /// <summary>
        /// Exclui uma política de corretagem do banco de dados.
        /// </summary>
        /// <param name="entity"></param>
        public void ExcluirPoliticaCorretagem(BusinessEntity.Parameter.FiltroPoliticaCorretagemChave entity)
        {
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("DELETE FROM TBOCORR_POLI");
            sql.AppendLine("WHERE");
            sql.AppendLine("    CD_POLITICA = :Codigo");
            sql.AppendLine("    AND DT_INICIAL = :DataInicial");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);

                this.DataBase.ExecuteNonQuery(command);
            }
        }
        /// <summary>
        /// Duplica uma política de corretagem
        /// </summary>
        /// <param name="entity"></param>
        public BusinessEntity.Parameter.FiltroPoliticaCorretagemChave DuplicarPoliticaCorretagem(BusinessEntity.Parameter.FiltroPoliticaCorretagemChave entity)
        {
            int codigoUltimaPolitica = this.ObterCodigoUltimaPolitica();            
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("INSERT INTO TBOCORR_POLI");
            sql.AppendLine("SELECT");
            sql.AppendLine("    :codigoUltimaPolitica + 1,");
            sql.AppendLine("    DT_INICIAL,");
            sql.AppendLine("    DT_FINAL,");
            sql.AppendLine("    DS_POLITICA,");
            sql.AppendLine("    CD_TIPO_APLIC,");
            sql.AppendLine("    CD_TABELA,");
            sql.AppendLine("    CD_TABELA_BENEF,");
            sql.AppendLine("    IN_CTRL_BENEF,");
            sql.AppendLine("    IN_VERIF");
            sql.AppendLine("FROM");
            sql.AppendLine("    TBOCORR_POLI");
            sql.AppendLine("WHERE");
            sql.AppendLine("    CD_POLITICA = :Codigo");
            sql.AppendLine("    AND DT_INICIAL = :DataInicial");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "codigoUltimaPolitica", DbType.Int32, codigoUltimaPolitica);
                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);

                this.DataBase.ExecuteNonQuery(command);               
            }

            return new BusinessEntity.Parameter.FiltroPoliticaCorretagemChave
            {
                Codigo = codigoUltimaPolitica + 1,
                DataInicial = entity.DataInicial
            };
        }

        /// <summary>
        /// Ajusta dados na ultima política de corretagem atualizando a data final da mesma
        /// com a ultima data anterior ao inicio da nova vigência.
        /// </summary>
        /// <param name="entity"></param>
        public void AjustarUltimaPoliticaCorretagem(BusinessEntity.Parameter.FiltroPoliticaCorretagemChave entity)
        {
            StringBuilder sql = new StringBuilder();

            sql.AppendLine("UPDATE");
            sql.AppendLine("    TBOCORR_POLI");
            sql.AppendLine("SET");
            sql.AppendLine("    DT_FINAL = :DataInicial"); //AddDays(-1) Lembrar
            sql.AppendLine("WHERE");
            sql.AppendLine("    CD_POLITICA = :Codigo");
            sql.AppendLine("AND	DT_INICIAL = (SELECT MAX(DT_INICIAL) FROM TBOCORR_POLI A WHERE A. CD_POLITICA = CD_POLITICA)");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                this.DataBase.AddInParameter(command, "DataInicial", DbType.DateTime, entity.DataInicial);

                this.DataBase.ExecuteNonQuery(command);
            }
        }
        /// <summary>
        /// Verifica se existe uma política de corretagem já cadastrada conforme os
        /// criterios do filtro.
        /// 
        /// Retorno: True = Existe politica; False = Não existe política
        /// </summary>
        /// <param name="entity"></param>
        public bool VerificarExistenciaPolitica(BusinessEntity.Parameter.FiltroPoliticaCorretagemChave entity)
        {
            object retorno = null;

            StringBuilder sql = new StringBuilder();

            sql.AppendLine("SELECT");
            sql.AppendLine("    DECODE(COUNT(1), 0, 0, 1)");
            sql.AppendLine("FROM");
            sql.AppendLine("    TBOCORR_POLI");
            sql.AppendLine("WHERE");
            sql.AppendLine("    CD_POLITICA = :Codigo");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "Codigo", DbType.Int32, entity.Codigo);
                retorno = this.DataBase.ExecuteScalar(command);
            }

            return (Int32.Parse(retorno.ToString()) != 0);
        }
        /// <summary>
        /// Obtem o codigo da ultima política de corretagem cadastrada no banco de dados.
        /// </summary>
        private int ObterCodigoUltimaPolitica()
        {
            object retorno;

            StringBuilder sql = new StringBuilder();

            sql.AppendLine("SELECT");
            sql.AppendLine("    NVL(MAX(CD_POLITICA),0)");
            sql.AppendLine("FROM");
            sql.AppendLine("    TBOCORR_POLI");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                retorno = this.DataBase.ExecuteScalar(command);
            }

            return Convert.ToInt32(retorno);
        }
        /// <summary>
        /// Verifica no banco de dados se existe outra politica de corretagem com a mesma
        /// data inicial.
        /// </summary>
        /// <param name="dataInicial"></param>
        public bool ExisteOutraPoliticaComDataInicial(DateTime dataInicial)
        {
            object retorno = null;

            StringBuilder sql = new StringBuilder();

            sql.AppendLine("SELECT");
            sql.AppendLine("    DECODE(COUNT(1),0,0,1)");
            sql.AppendLine("FROM");
            sql.AppendLine("    TBOCORR_POLI");
            sql.AppendLine("WHERE");
            sql.AppendLine("    DT_INICIAL = :dataInicial");

            using (DbCommand command = this.DataBase.GetSqlStringCommand(sql.ToString()))
            {
                this.DataBase.AddInParameter(command, "dataInicial", DbType.DateTime, dataInicial);
                retorno = this.DataBase.ExecuteScalar(command);
            }

            return (Int32.Parse(retorno.ToString()) != 0);
        }

        #endregion
    }
}